SQLServer アーキテクチャ CPUリソース最適化
前提知識
CPUはプロセスやスレッドから並行で利用されてる。
OSはプロセス・スレッドに対していい感じに細かく切り替えながらCPUを割り当ててる。(タイムスライシング) この切り替えるタイミングは色々あるが...基本的には以下
1. 元々定められたた利用タイムの上限に達した(上限といってもめっちゃ細かいmm秒的な世界)
2. CPU利用スレッドでIO待ちが発生した
など
SQL Serverは1プロセスとマルチスレッドで動作する
SQL Serverは1つのインスタンスごとに1プロセスが作成されるようになってる。
そして、1プロセスから様々な種類・数のスレッドが生成される。
SQL Server独自スケジューラ
Windows OSでのCPUタイムスライスを担当するスケジューラをWindowsスケジューラと呼ぶ。
このスケジューラ、OSが把握できる待ちなどを感知したら、それを元にスライシングを実行できるのだが...
SQL Server独自の待ちなどは把握することができない。
そのため、WIndowsスケジューラから見たら、SQL Serverで待ち状態があったとしても対象スレッドがまだCPUを利用中だと思い込み、利用上限時間までCPUリソースを与え続けてしまう。
これにより無駄なCPU消費が発生することになる。
ということでSQL Serverは考えて、SQL Server専用のスレッドスケジューラを作った。
このSQLOSスケジューラは、SQLServerプロセス内で動作するユーザープログラムとなってる。
何が言いたいかというと...
独自のスケジューラと言ってもあくまでWindowsスケジューラの上で動いてるんだよってことを言いたい。
つまりSQS Server用にWindowsスケジューラを差し替えてるとかでは無いのである。
Windowsスケジューラは、カーネルプログラムであり、全プロセスのCPUリソース割り当てを担ってる番長。
SQLOSスケジューラは、あくまでプロセス内で動作する一機能でしかない。
ただ、プロセス内で動くと言っても、うまいこと並列タスクを管理して、Windowsスケジューラの機能を活用しながら、タスクごとのCPU仕様効率を上げに行ってる。
SQLOSスケジューラのメンバー
スケジューラ
管理棟・マネージャー的な役割のやつ。
具体的にはワーカーを管理して、いい感じに各ワーカーにCPUを割り当てるようにする。
スケジューラは、論理CPU1つに対して1つ作られる。
ワーカー
CPUをスケジューラから当てられる実行最小単位。
基本的には1タスク(クエリ)に対して1ワーカーが当てられる。
つまり、あるクライアントからクエリが実行されたら、その接続に対してワーカーが当てられる。
まあ、1タスクに対して2つ以上のワーカーが当てられることもあるらしい。
並列実行的な何かかな?あり得る。
また、ワーカー:OSスレッド = 1:1の関係でもある。
ワーカースレッドプール
いわゆるワーカーの倉庫。
アクティブ/ノンアクティブなワーカーを把握してるはず。
また、max_worker_threadsという設定から、ワーカー最大保持数も決まってる。
ちなみに、スケジューラ1つに対しての最大ワーカー数は、CPUが複数ある場合「max_worker_threads / CPU数」になる。
ランナブルキュー
CPUをスケジューラから当てられる順番待ちのワーカーキュー。
スケジューラごとに1つ存在するってのを認識しておきなさいよ。
CPUを使いたい複数のワーカーがお利口さんに順番に並んでる。
ワークリクエストキュー
クライアントからのリクエストに対して当てれる「ワーカー」が無い状態の際に利用されるキュー。
クライアントの要求順にリクエストをキューに並べておく。
I/Oリクエストキュー
CPU利用中にI/Oリクエストを発行したワーカーが送られるキュー。
ここでI/Oリクエストが完了するのを待ってる。
完了したら、ランナブルキューに再度送られる。
ウェイターリスト
こいつだけ注意!!!
これはテーブルやレコードごとに作られるキュー。
そのデータの使用権をワーカーの欲しいと言った順に並ばせるキュー。
ロックなどがその一例。
ロックが解放されるまでは、ウェイターリストにならんだワーカーは動けない。
SQLOSスケジューラの動き
これは「絵で見てわかるSQLServerの仕組み - 第1章 -」を読んでほしい。
日々進化してる
SQLOSスケジューラは、2016, 2017, 2019と進むごとに進化して、CPU使用効率性も上がっている。
そこら辺も意識しながら使ってみるとよし。